using System;
using System.Collections.Generic;
using System.Diagnostics;
using TAAlert.CommonUtils;

namespace TAAlert.BackTest
{
    class TwoEMAStrategy : Strategy
    {
        static private readonly TraceSwitch traceM = new TraceSwitch("TwoEMAStrategy", "Debug info for Strategy class");
        private List<double> emaShortM;     // Short exp moving average. The same size as prices
        private List<double> emaLongM;      // Long exp. moving average. The same size as prices
        private List<double> volM;          // volatilities. The same size as prices
        private double volTreasholdM;       // volatility cut-out value

        /// <summary>Two EMA strategy with volatility cut-out. For volatility below volTreashold BUY if emaShort above emaLong, SELL if emaShort below emaLong. Neutral above volatilityTreashod</summary>
        /// <param name="nEmaShort">short EMA period</param>
        /// <param name="nEmaLong">long EMA period</param>
        /// <param name="volTreashold">volatility treashold</param>
        /// <param name="startDate">strategy start date</param>
        /// <param name="endDate">strategy end date</param>
        /// <param name="prices">dated signal prices</param>
        public TwoEMAStrategy(int nEmaShort, int nEmaLong, double volTreashold, DateTime startDate, DateTime endDate, SortedList<DateTime, double> prices)
            : base(startDate, endDate, prices, traceM)
        {
            Debug.WriteLineIf(traceM.TraceInfo, "--> Entering TwoEmaStrategy(" + nEmaShort + ", " + nEmaLong + ", volT=" + volTreashold + ", " + startDate.ToShortDateString() + ", " + endDate.ToShortDateString() + ", prices)");
            // calculate EMAs
            this.emaShortM = EMAEvaluator.calcEMAArray(this.Prices.Values, nEmaShort);
            this.emaLongM = EMAEvaluator.calcEMAArray(this.Prices.Values, nEmaLong);
            this.volM = EMAEvaluator.calcEMAVolatilityArray(this.Prices.Values);
            this.volTreasholdM = volTreashold;

            Debug.Assert(emaShortM.Count == this.Prices.Count, "Short EMA and prices must have the same length");
            Debug.Assert(emaLongM.Count == this.Prices.Count, "Long EMA and prices must have the same length");
            Debug.Assert(volM.Count == this.Prices.Count, "Volatility and prices must have the same lenght");

        }

        /// <summary>Generate list of investment positions. (+1 long, -1 short, 0 neutral)</summary>
        /// <returns>List of dated positions. The positions are established on date close and affect only the next day perofmrance.</returns>
        override public SortedList<DateTime, int> generate()
        {
            Debug.WriteLineIf(traceM.TraceInfo, "--> Entering TwoEMAStrategy.generate()");
            Debug.Indent();
            int n = this.EndIx - this.StartIx + 1;

            SortedList<DateTime, int> pos = new SortedList<DateTime, int>(n);
            Debug.WriteLineIf(traceM.TraceVerbose, "date,emaShort,emaLong,vol,pos");
            for (int ix = this.StartIx; ix <= this.EndIx; ++ix)
            {
                DateTime date = this.Prices.Keys[ix];
                int signal = (int)EMAEvaluator.emaVolCutSignal(emaShortM[ix], emaLongM[ix], this.volM[ix], this.volTreasholdM);   //EMAEvaluator.emaSignal(emaShortM[ix], emaLongM[ix]);
                pos.Add(date, signal);
                Debug.WriteLineIf(traceM.TraceVerbose, date.ToShortDateString() + "," + emaShortM[ix].ToString(".##") + "," + emaLongM[ix].ToString(".##") + "," + volM[ix].ToString("P1") + "," + signal);
            }
            Debug.WriteLineIf(traceM.TraceInfo, "... generated " + pos.Count + " signals");
            Debug.Unindent();

            return pos;
        }
    }
}
